#ifndef _HEAD_H_
#define _HEAD_H_
#include "my_fun.h"

//----------------------------------------------------
#define CONFIG_MAX_LEN 256
//配置文件中要读取的数据的结构体
typedef struct {
    char log_path[3][CONFIG_MAX_LEN];
    char server_ip[CONFIG_MAX_LEN];
    char server_port[CONFIG_MAX_LEN];
    char data_base_user[CONFIG_MAX_LEN];
    char data_base_pwd[CONFIG_MAX_LEN];
    char data_base_name[CONFIG_MAX_LEN];
    int pthread_count;
}config;

int read_config(const char *file_name,config *config_info);

//----------------------------------------------------

//初始化日志
#define INIT_LOG(log_path) init_log(log_path)


//打印LOG宏函数
//参数一：日志等级，enum类型
//参数二：需要打印的字符信息
#define LOG(LEVEL,STR) write_log(LEVEL,STR,__FILE__,__FUNCTION__,__LINE__)



//默认打印日志等级
#define DEFAULT_LEVEL ERROR
//日志等级
typedef enum {
    INFO,
    WARING,
    ERROR
}LOG_LEVEL;


//初始化日志
int init_log(const char  log_path[3][256]);


//获取当前时间
void get_current_time(char* buf,ssize_t len);


//关闭日志文件
void close_log();

//写日志
void write_log(LOG_LEVEL level,const char * str,const char * file_name,const char * func,int line);

//---------------------------------------------------------------------------------------------------








typedef struct transmit_s{
   char flag[64];
   char name[64];
   char password[64];
   char command[64];
   char argument[64];
   char token[512];
}transmit_t;

// ******************* tcp相关函数 **************

int tcp_init(int *socket_fd,char *ip,char *port);

// ！！！！！！！这两个函数 只能 用来传递字符串 ！！！！！！！！
// 函数返回值是发送/接收到的字符个数
// recv_train 返回0说明对端关闭网络连接
int recv_train(char* buf, int net_fd);
int send_train(char* buf, int net_fd);



// ******************  epoll相关函数 ******************

int epoll_add(int epoll_fd, int fd);
int epoll_del(int epoll_fd, int fd);


// ************** 生产者消费者队列相关内容 *************

// 这个是队列中的数据域
typedef struct client_info_s{
    int net_fd;               // 客户端的网络文件描述符
    char name[64];           // 客户端的的用户名，可以用这个用户名查数据库
    char command[64];        // 各种命令
    char argument[64];       // 命令的参数
}client_info_t;

// 真实队列中的节点
typedef struct task_s{
    client_info_t client_info;
    struct task_s* next;
}task_t;

// 队列本身结构体
typedef struct task_queue_s{
    task_t* head;
    task_t* end;
    int size;
}task_queue_t;

int en_task_queue(task_queue_t* ptask_queue, client_info_t* pclient_info);
int de_task_queue(task_queue_t* ptask_queue, client_info_t* pclient_info);



// ***************** 线程相关内容 *********************

// 主线程和子线程的共享资源
typedef struct shared_resource_s{
    pthread_cond_t task_queue_cond;
    pthread_mutex_t task_queue_mutex;
    task_queue_t task_queue;
    //char host[32];               // 数据库的ip地址
    char user[32];                 // 数据库的用户名
    char password[32];             // 数据库的密码
    char data_base[32];            // 要连接的数据库名字
}shared_resource_t;
// TODO 需要写一个销毁函数，销毁锁，条件变量之类的
int shared_resource_init(shared_resource_t* p,const char* user,const char* password,const char*data_base);



// 线程池相关
typedef struct pool_data_s{
    pthread_t* list;
    int num;
}pool_data_t;
// TODO　这里需要一个销毁函数，回收子线程资源和释放pool_data申请的堆空间
int pool_init(pool_data_t* pool_data, int num, shared_resource_t* p);

// 子线程主函数
void* thread_main(void* p);
// 子线程工作函数
int dowork(shared_resource_t* pshared_resource, MYSQL* mysql);



//******************* 服务端初始化相关 ****************
// 服务端初始化函数，有配置文件之后改这里
int server_init(config * config_info,shared_resource_t* pshared_resource, 
                pool_data_t* pool_data, int* socket_fd, MYSQL** mysql);



//**************** 超时踢出队列相关 ********************

// 存储net_fd (key) 和 超时踢出队列索引 index (val) 的哈希表
typedef struct hash_node_s{
    int net_fd;
    int index;
    struct hash_node_s* next;
}hash_node_t;

typedef struct hash_map_s{
    int size;
    int capacity; 
    long int seed;
    hash_node_t** map;     // 这里是存储hash_node_t* 的数组
}hash_map_t;

// 初始化函数
int hash_map_init(hash_map_t* hash_map, int size);
// 添加一个元素
int hash_map_add(hash_map_t* hash_map, int net_fd, int index);
// 删除一个元素
int hash_map_del(hash_map_t* hash_map, int net_fd, int* index);


#define TIMEOUT 30  // 这个是超时踢出的秒数

// 超时踢出队列的链表结点
typedef struct timeout_node_s{
    int net_fd;
    struct timeout_node_s* next;
}timeout_node_t;

// timeout_node_t* timeout_queue[TIME_OUT];

// 添加一个元素
int timeout_add(timeout_node_t** timeout_queue, int net_fd, int index);
// 删除一个元素
int timeout_del(timeout_node_t** timeout_queue, int net_fd, int index);
// 按照索引删除很多元素
int timeout_del_index(timeout_node_t** timeout_queue, int index, hash_map_t* hash_map);




//****************** 服务端请求处理函数 ********************
int require_handler(int net_fd, shared_resource_t* pshared_resource,
                    MYSQL* mysql, int epoll_fd,
                    hash_map_t* hash_map, timeout_node_t** timeout_queue);


//****************** 短命令处理函数 ***********************
int ls_handler(client_info_t* pclient_info, MYSQL* mysql);
int cd_handler(client_info_t* pclient_info, MYSQL* mysql);
int pwd_handler(client_info_t* pclient_info, MYSQL* mysql);
int rm_handler(client_info_t* pclient_info, MYSQL* mysql);
int mkdir_handler(client_info_t* pclient_info, MYSQL* mysql);


//***************** 长命令处理函数 ***********************
// ！！！！！！！长命令需要在完成任务后在函数体内部关闭网络文件描述符！！！！！！！
int puts_handler(client_info_t* pclient_info, MYSQL* mysql);
int gets_handler(client_info_t* pclient_info, MYSQL* mysql);

//***************** 登录和注册函数 ************************
int register_server_handler(MYSQL*mysql,int net_fd,transmit_t*transmit);
int login_server_handler(MYSQL*mysql,int net_fd,transmit_t *transmit);
int create_token(char token[],transmit_t *transmit);
int decrypt_token(transmit_t*transmit,int net_fd);

//********************tool.c******************************
//user表中的数据，用于存放查询结果
typedef struct user_s{
    int user_id;
    char *user_name;
    char *pwd_hash;
    char *salt;
    int file_id;
}user_t;


//file表中的数据，用于存放查询file表中的数据
typedef struct file_s{
    int file_id;
    int parent_id;
    char *file_name;
    int user_id;
    char *file_hash;
    char *file_types;
    char *file_path;
    int cancel_flag;
}file_t;

//通过用户名查user表
//第二个参数为查询条件（用户名）
//第三个参数为获得的查询结果
//!!!!只能通过通用户名来查询，查询必须使用select *,结构体中会存放查询到的一行数据！！！！！
//只会查询到一条数据
//若未查询到数据，返回-1
int select_user(MYSQL *mysql, char *name, user_t *user);  

//通过hash值查询file表
//第二个参数为查询条件（hash值）
//第三个参数为获得的查询结果
//！！！！！查询结果可能包含多条数据，只保留了第一条！！！！！！！
//若未查询到数据，返回-1  
int select_file(MYSQL *mysql, char *hash, file_t *file); 


//通过file_id查询file表
//通过file_id只能查到一条数据
//第二个参数为查询条件（file_id）
//第三个参数为获得的查询结果
//若未查询到数据，返回-1 
int fileid_select_file(MYSQL *mysql, int file_id, file_t *file);

//计算文件的hash值
int hash_sha1(char *file_hash_now, char *file_hash);   

#endif
